// json版深拷贝(缺点:没法拷贝函数/循环引用)
const obj = {
  id: 001,
  name: 'niko',
  stage: [1, 2, 3],
  info: {
    weight: '68kg',
    height: '175cm',
    sex: 'man'
  }
}

// 1.把对象进行json序列化
const s = JSON.stringify(obj)
console.log(s)
// 2.把对象解序列化,并赋值给另一个变量
const copyObj = JSON.parse(s)
console.log(copyObj)
// 3.通过全等符判断两个对象不是同一个地址
console.log(obj === copyObj)

console.log('----------------------------')

// 基础浅拷贝
const obj2 = {
  name: 'hikk',
  age: 18,
  sex: 'woman'
}

function clone (object) {
  // 1.创建空对象
  const copyObj = {}
  // 2.遍历原对象所有key,并将其值拷贝一份给copyObj
  for (const key in object) {
    console.log(key)
    copyObj[key] = object[key]
  }
  // 3.返回新对象
  return copyObj
}

let res = clone(obj2)
console.log(res)

console.log('----------------------------')

// 基础版深拷贝(缺点:没考虑数组的深拷贝)
function basicDeepCopy (target) {
  // 1.判断传入的值是不是对象
  if (typeof target === 'object') {
    // 2.创建新对象
    const cloneTarget = {}
    for (const key in target) {
      // 3.递归调用函数(深拷贝的核心!)
      cloneTarget[key] = basicDeepCopy(target[key])
    }
    // 5.返回拷贝后对象
    return cloneTarget
  } else {
    // 4.对于不是对象的数据,直接返回
    return target
  }
}

// 测试
const obj3 = {
  name: 'haha',
  age: 18,
  info: {
    height: '178cm',
    weight: '70kg'
  }
}

let res2 = basicDeepCopy(obj3)
console.log('基础版深拷贝', res2)

console.log('-------------------------------')

// 基础版改进(兼容深拷贝数组)
function basicClone (target) {
  // 1.判断是否是对象
  if (typeof target === 'object') {
    // 2.进一步判断是不是数组对象
    // 是数组就返回一个空数组,是对象就返回一个空对象
    let cloneTarget = Array.isArray(target) ? [] : {}
    // 3.遍历原对象赋值给cloneTarget,通过递归调用实现深拷贝
    for (const key in target) {
      cloneTarget[key] = basicClone(target[key])
    }
    // 4.返回拷贝后的副本(新内存空间存放)
    return cloneTarget
  } else {
    // 5.如果不是对象,直接返回原始值
    return target
  }
}

// 测试
let obj4 = {
  a: [1, 2, 3],
  b: {
    name: 'nini',
    age: 16
  },
  c: 'hello'
}
let res4 = basicClone(obj4)
console.log('基础版深拷贝(包括数组)', res4)


console.log('-------------------------------')

// 深拷贝(解决循环引用)
// 此处使用WeakMap弱引用,函数执行后对象被释放
function clone (target, map = new WeakMap()) {
  if (typeof target === 'object') {
    let cloneTarget = Array.isArray(target) ? [] : {}
    if (map.get(target)) {
      console.log(map)
      return map.get(target)
    }
    map.set(target, cloneTarget)
    for (const key in target) {
      cloneTarget[key] = clone(target[key], map)
    }
    return cloneTarget
  } else {
    return target
  }
};

const attrInfo = {
  // 属性名
  attrName: '',
  // 属性值
  attrValueList: ['a', 'b', 'c'],
  categoryId: 0,   // 三级分类的id
  categoryLevel: 3  // 告诉服务器是第几级的菜单属性
}

let res5 = clone(attrInfo)
console.log(res5)


// 通过自定义函数实现深拷贝
function deCopy (target, source) {
  // 1.通过遍历拿到source中所有的属性
  for (let key in source) {
    // 2.取出当前遍历到的属性对应的取值
    let sourceValue = source[key]
    // 3.判断当前的取值是否是引用数据类型
    if (sourceValue instanceof Object) { // 如果是引用数据类型, 那么要新建一个存储空间保存
      // 4.通过sourceValue.constructor拿到这个对象的构造函数的类型, 然后新建这个对象或数组
      let subTarget = new sourceValue.constructor
      target[key] = subTarget
      // 5.再次调用拷贝, 将遍历到的属性的取值拷贝给新建的对象或者数组
      deCopy(subTarget, sourceValue)
    } else { // 如果不是引用数据类型, 之间将属性拷贝即可
      target[key] = sourceValue
    }
  }
}
